#ifndef UnstructMG_OPERATOR_HPP
#define UnstructMG_OPERATOR_HPP

#include "par_Vector.hpp"

// 虚基类Operator，需要子类重写Mult()，如有必要还需重写析构函数
// 算子需要两种精度：数据的存储精度data_t，和计算时的精度calc_t
template<typename idx_t, typename calc_t, int dof>
class Operator {
protected:
    // 截断矩阵/算子元素到16位精度存储（模拟）
    virtual void truncate() = 0;
public:
    Operator() {  }
    virtual ~Operator() {}
    // 带零初值优化的接口，由上层调用者决定是否要使用零初值的
    virtual void Mult(const par_Vector<idx_t, calc_t, dof> & input, 
                            par_Vector<idx_t, calc_t, dof> & output, bool use_zero_guess) const = 0;
};

template<typename idx_t, typename setup_t, typename calc_t, int dof>
class Solver : public Operator<idx_t, calc_t, dof> {
protected:
    mutable bool zero_guess = false;// 初始解是否为0
    mutable calc_t weight = 1.0;
    bool setup_called = false;
    // 真正的函数实现
    virtual void Mult_ipl(const par_Vector<idx_t, calc_t, dof> & input, 
                                par_Vector<idx_t, calc_t, dof> & output) const = 0;
public:
    double setup_time = 0.0;
    Solver(bool use_zero_guess = false): Operator<idx_t, calc_t, dof>() {zero_guess = use_zero_guess;} 
    virtual void SetOperator(const Operator<idx_t, setup_t, dof> & op) = 0;
    virtual void SetRelaxWeight(calc_t wt) {weight = wt;}
    // 基类的统一接口，设置成员变量来决定是否使用零初值的优化
    virtual void Mult(const par_Vector<idx_t, calc_t, dof> & input, 
                            par_Vector<idx_t, calc_t, dof> & output, bool use_zero_guess) const {
        this->zero_guess = use_zero_guess;
        // this->zero_guess = false;
        Mult_ipl(input, output);
        this->zero_guess = false;// reset for safety concern
    }
};

#endif